/**
 * 
 * Copyright (C) 2015 by Elcom Software Company
 *
 * @id: JSONPacker.java, Mar 19, 2015
 *
 */
package com.nip.commons.json.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import com.nip.commons.json.abs.Json;
import com.nip.commons.json.annotations.JSONElement;
import com.nip.commons.json.annotations.JSONObject;
import com.nip.commons.json.commons.JSONCommon;
import com.nip.commons.json.commons.JSONCommon.JSONType;
import com.nip.commons.json.exception.JSONException;

/**
 * @author ThangNM<thangnm@elcom.com.vn>
 * 
 * @version v
 */
public class JSONGenerater {

    public static String toJson(Object jsonObject) throws JSONException {
        if (jsonObject == null) {
            throw new JSONException("Json object is null");
        }

        JSONObject jo = jsonObject.getClass().getAnnotation(JSONObject.class);

        if (jo == null) {
            throw new JSONException("Object is not json object.");
        }

        StringBuilder sb = new StringBuilder("{");

        JSONElement element = null;
        try {
            for (Method method : jsonObject.getClass().getMethods()) {
                element = method.getAnnotation(JSONElement.class);

                if (element != null) {
                    sb.append("\"" + element.name() + "\":");
                    // Kieu du lieu nguyen thuy
                    if (element.type() == JSONType.PRIMITIVE) {

                        getPValue(jsonObject, sb, method);

                        // Kieu du lieu la mot json object
                    } else if (element.type() == JSONType.JSON_OBJECT) {

                        try {
                            Object value = method.invoke(jsonObject,
                                    new Object[] {});
                            if (value == null) {
                                sb.append("null" + ",");
                                continue;
                            }

                            sb.append(JSONGenerater.toJson(value) + ",");
                        } catch (NullPointerException e) {
                            sb.append("null" + ",");
                        }

                        // Kieu du lieu la mot mang du lieu nguyen thuy
                    } else if (element.type() == JSONType.ARRAY) {

                        getAValue(jsonObject, sb, method);

                        // Kieu du lieu la mot mang du lieu json object
                    } else if (element.type() == JSONType.JSON_ARRAY) {

                        sb.append("[");
                        try {
                            Object[] values = (Object[]) method.invoke(
                                    jsonObject, new Object[] {});
                            for (Object ob : values) {
                                if (ob == null) {
                                    continue;
                                }

                                sb.append("{\"" + element.name() + "\":"
                                        + toJson(ob) + "},");
                            }

                        } catch (NullPointerException e) {

                        }
                        sb.append("]" + ",");

                    } else {
                        throw new JSONException("Unsuport JSONType.");
                    }
                }

            }
        } catch (Exception e) {
            throw new JSONException(e);
        }

        sb.append("}");

        return sb.toString().replace(",}", "}").replace(",]", "]");
    }

    /**
     * @param jsonObject
     * @param sb
     * @param method
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private static void getAValue(Object jsonObject, StringBuilder sb,
            Method method) throws IllegalAccessException,
            InvocationTargetException {

        sb.append("[");
        try {
            Object[] values = (Object[]) method.invoke(jsonObject,
                    new Object[] {});
            for (Object ob : values) {
                sb.append("{\"" + JSONCommon.ELEMENT_DEFAULT + "\":");
                if (ob.getClass().getName().equals(String.class.getName())) {
                    sb.append("\"" + ob + "\"},");
                } else {
                    sb.append(ob + "},");
                }
            }

        } catch (NullPointerException e) {
        }
        sb.append("],");
    }

    /**
     * @param jsonObject
     * @param sb
     * @param method
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private static void getPValue(Object jsonObject, StringBuilder sb,
            Method method) throws IllegalAccessException,
            InvocationTargetException {
        try {
            Object value = method.invoke(jsonObject, new Object[] {});
            if (value.getClass().getName().equals(String.class.getName())) {
                sb.append("\"" + value + "\",");
            } else {
                sb.append(value + ",");
            }
        } catch (NullPointerException e) {
            sb.append("null" + ",");
        }
    }

    public static String toArrayJson(Object[] jsonObject) throws JSONException {
        if (jsonObject == null || jsonObject.length == 0) {
            return "[]";
        }

        JSONObject jo = jsonObject[0].getClass()
                .getAnnotation(JSONObject.class);

        if (jo == null) {
            throw new JSONException("Object not define JsonObject");
        }

        StringBuilder sb = new StringBuilder("[");
        String name = jo.name();

        if (jsonObject[0] instanceof Json) {
            for (Object ob : jsonObject) {
                sb.append("{\"" + name + "\":");
                sb.append(((Json) ob).toJson());
                sb.append("},");
            }
        } else {
            for (Object ob : jsonObject) {
                sb.append("{\"" + name + "\":");
                sb.append(toJson(ob));
                sb.append(",}");
            }
        }

        sb.append("]");

        return sb.toString().trim().replace(",]", "]");
    }

    public static void main(String[] args) {

    }

}
